/*
 * Copyright (c) 2010-2011, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ALKES_GRAPH_ELEMENT_H_INCLUDED_
#define ALKES_GRAPH_ELEMENT_H_INCLUDED_

#include "alkes/graph/internal.h"
#include "alkes/graph/GraphicsContext.h"
#include "alkes/graph/HitTestContext.h"
#include "alkes/graph/UpdateContext.h"
#include "alkes/graph/Resource.h"

namespace alkes {

class Clippable;
class Visual;
class Composite;

/// \addtogroup scenegraph
//@{

class AL_GRAPH_EXPORT Element
{
    AL_DECLARE_ROOT_CLASS(Element);

public:
    Element();
    virtual ~Element() = 0;

    void setDirty(bool is_dirty);
    bool isDirty() const;

    void setVisible(bool is_visible);
    bool isVisible() const;

    bool isConstant() const;

    void setHittable(bool is_hittable);
    bool isHittable() const;

    bool isRendering() const;
    bool isUpdating() const;

    bool isModifiable() const;
    bool isComposite() const;

    bool isDrawable() const;

    bool hasSize() const;

    bool needClear() const;
    void setClear(bool need_clear);

protected:

    void denyModify();
    void allowModify();

    template<class T, class U>
    bool setProperty(T& dst, const U& src)
    {
        bool ret = false;
        if (dst != src)
        {
            dst = src;
            setDirty(true);
            ret = true;
        }
        return ret;
    }

    template<class T, class U>
    bool setProperty(resource_ptr<T>& dst, const U& src)
    {
        bool ret = false;
        if (dst != src)
        {
            dst.registerResource(this, src);
            setDirty(true);
            ret = true;
        }
        return ret;
    }

    void setFlag(uint32_t idx, bool is_on = true);
    void clearFlag(uint32_t idx);
    bool flag(uint32_t idx) const;

private:
    friend class Clippable;
    friend class Visual;
    friend class Composite;

    enum Flag
    {
        FLAG_DIRTY          =  0,
        FLAG_VISIBLE        =  1,
        FLAG_CONSTANT       =  2,
        FLAG_HITTABLE       =  3,
        FLAG_CLIP_OFFSET    =  4,
        FLAG_RENDERING      =  5,
        FLAG_UPDATING       =  6,
        FLAG_HITTESTING     =  7,
        FLAG_UNMODIFIABLE   =  8,
        FLAG_IS_COMPOSITE   =  9,
        FLAG_DISABLE_CLIP   = 10,
        FLAG_DRAWABLE       = 11,
        FLAG_HAS_SIZE       = 12,
        FLAG_CLEAR          = 13,

        FLAG_MAXIMUM = 16,
    };

    void setSystemFlag(uint32_t idx);
    void clearSystemFlag(uint32_t idx);
    bool systemFlag(uint32_t idx) const;

private:
    TBitArray<uint32_t> flag_;
};

#define AL_LOCK_SELF()      denyModify()
#define AL_UNLOCK_SELF()    allowModify()

#define AL_DECLARE_ELEMENT(name, parent)    AL_DECLARE_CLASS(name, parent)

#if !defined(__GNUC__)
#define AL_PRINT_NODE(fmt, ...) LOGD("%s(0x%08p)" fmt, getClassName(), this __VA_ARGS__)
#else
#define AL_PRINT_NODE(fmt, ...) LOGD("%s(0x%08p)" fmt, getClassName(), this, ## __VA_ARGS__)
#endif

//#define AL_TRACE_UPDATE_NODE
//#define AL_TRACE_RENDER_NODE

//@}

}

#endif
